package com.hz.example.lib;

import com.alibaba.fastjson.JSON;
import com.hz.example.pojo.Student;
import com.hz.example.pojo.StudentVo;
import com.hz.example.util.StopWatch;
import ma.glasnost.orika.impl.ConfigurableMapper;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.collections.MapUtils;
import org.junit.Test;
import org.springframework.beans.BeanUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 对象赋值
 *
 * @author hezhao created on 2019/12/14 14:14
 */
public class TestBeanCopy {

    private static final ConfigurableMapper orikaMapper = new ConfigurableMapper();

    @Test
    public void testBeanToVo() {
        StopWatch stopWatch = new StopWatch("测试Bean复制效率");
        Student stu = Student.builder().name("王五").age(44).build();

        stopWatch.start("OrikaMapper");
        StudentVo studentVo = orikaMapper.map(stu, StudentVo.class);
        System.out.println(studentVo);
        stopWatch.stop();

        stopWatch.start("Spring BeanUtils");
        StudentVo studentVo1 = new StudentVo();
        // 排除age属性
        BeanUtils.copyProperties(stu, studentVo1, "age");
        System.out.println(studentVo1);
        stopWatch.stop();

        try {
            stopWatch.start("Apache BeanUtils");
            StudentVo studentVo2 = new StudentVo();
            org.apache.commons.beanutils.BeanUtils.copyProperties(studentVo2, stu);
            System.out.println(studentVo2);
            stopWatch.stop();
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }

        System.out.println("\n" + stopWatch.prettyPrint());
    }

    @Test
    public void testBeanToMap() {
        StopWatch stopWatch = new StopWatch("测试Bean转Map效率");
        Student stu = Student.builder().name("王五").age(44).build();

        stopWatch.start("JSON.parseObject");
        Map map1 = JSON.parseObject(JSON.toJSONString(stu), Map.class);
        System.out.println(map1);
        stopWatch.stop();

        stopWatch.start("Apache BeanMap");
        Map<String, Object> map2 = beanToMap(stu);
        System.out.println(map2);
        stopWatch.stop();

        stopWatch.start("Java.beans.Introspector");
        Map<String, Object> map3 = bean2map(stu);
        System.out.println(map3);
        stopWatch.stop();

        System.out.println("\n" + stopWatch.prettyPrint());
    }

    @Test
    public void testMapToBean() {
        StopWatch stopWatch = new StopWatch("测试Map转Bean效率");
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("name", "李四");
        map.put("age", 22);

        stopWatch.start("JSON.parseObject");
        Student student = JSON.parseObject(JSON.toJSONString(map), Student.class);
        System.out.println(student);
        stopWatch.stop();

        stopWatch.start("Apache BeanUtils.populate");
        Student student1 = mapToBean(map, Student.class);
        System.out.println(student1);
        stopWatch.stop();

        stopWatch.start("Java.beans.Introspector");
        Student student2 = map2bean(map, Student.class);
        System.out.println(student2);
        stopWatch.stop();

        System.out.println("\n" + stopWatch.prettyPrint());
    }


    /**
     * Bean 2 Map
     *
     * @param stu
     * @return
     */
    private static Map<String, Object> beanToMap(Student stu) {
        BeanMap beanMap = new BeanMap(stu);
        Map<String, Object> map = new LinkedHashMap<>();
        for (Map.Entry<Object, Object> entry : beanMap.entrySet()) {
            map.put((String) entry.getKey(), entry.getValue());
        }
        map.remove("class");
        return map;
    }

    /**
     * 二：将javabean转换为map
     * @param bean
     * @return
     * @throws Exception
     */
    public static Map<String, Object> bean2map(Object bean) {
        if (bean == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        try {
            //获取类的属性描述器
            BeanInfo beaninfo = Introspector.getBeanInfo(bean.getClass(), Object.class);
            //获取类的属性集
            PropertyDescriptor[] pro = beaninfo.getPropertyDescriptors();
            for (PropertyDescriptor property : pro) {
                //得到属性的name
                String key = property.getName();
                // 过滤class属性
                if (!"class".equals(key)) {
                    Method get = property.getReadMethod();
                    //执行get方法得到属性的值
                    Object value = get.invoke(bean);
                    map.put(key, value);
                }
            }
            return map;
        } catch (Exception e) {
            System.out.println("bean2map Error " + e);
        }
        return map;
    }

    /**
     * 一：map2javabean 把map对象转换为javabean
     * @param map
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T map2bean(Map<String, Object> map, Class<T> clazz) {
        if (MapUtils.isEmpty(map) || clazz == null) {
            return null;
        }
        try {
            //创建对象
            T object = clazz.newInstance();
            //获取类的属性描述器
            BeanInfo beaninfo = Introspector.getBeanInfo(clazz, Object.class);
            //获取类的属性集
            PropertyDescriptor[] pro = beaninfo.getPropertyDescriptors();
            for (PropertyDescriptor property : pro) {
                //获取属性的名字
                String key = property.getName();
                if (map.containsKey(key)) {
                    //得到属性name在map中对应的value。
                    Object value = map.get(key);
                    //得到属性的set方法
                    Method set = property.getWriteMethod();
                    //接下来将map的value转换为属性的value
                    //执行set方法
                    set.invoke(object, value);
                }
            }
            return object;
        } catch (Exception e) {
            System.out.println("map2bean Error " + e);
        }
        return null;
    }

    // Map --> Bean 2: 利用org.apache.commons.beanutils 工具类实现 Map --> Bean
    public static <T> T mapToBean(Map<String, Object> map, Class<T> clazz) {
        if (MapUtils.isEmpty(map) || clazz == null) {
            return null;
        }
        try {
            //创建对象
            T object = clazz.newInstance();
            org.apache.commons.beanutils.BeanUtils.populate(object, map);
            return object;
        } catch (Exception e) {
            System.out.println("map2Bean2 Error " + e);
        }
        return null;
    }

}
